winbrew_engines\windows\exe/
install.rs1use anyhow::{Context, Result, bail};
2use std::fs;
3use std::path::Path;
4use std::process::Command;
5use tracing::warn;
6
7use crate::models::catalog::package::CatalogInstaller;
8use crate::models::install::engine::{EngineInstallReceipt, EngineKind, EngineMetadata};
9
10use super::NATIVE_EXE_SUCCESS_EXIT_CODES;
11use super::metadata::{NativeExeInstallMetadata, capture_native_exe_metadata};
12use super::switches::build_install_args;
13use super::validation::validate_install_inputs;
14
15pub(crate) fn install(
21 installer: &CatalogInstaller,
22 download_path: &Path,
23 install_dir: &Path,
24 package_name: &str,
25) -> Result<EngineInstallReceipt> {
26 validate_install_inputs(download_path, install_dir, package_name)?;
27
28 fs::create_dir_all(install_dir)
29 .with_context(|| format!("failed to create {}", install_dir.display()))?;
30
31 let args = build_install_args(installer, install_dir, package_name)?;
32
33 let status = Command::new(download_path)
34 .current_dir(download_path.parent().unwrap_or(Path::new(".")))
35 .args(&args)
36 .status()
37 .with_context(|| {
38 format!("failed to launch native executable installer for {package_name}")
39 })?;
40
41 let exit_code = status.code().ok_or_else(|| {
42 anyhow::anyhow!("native executable installer terminated without an exit code")
43 })?;
44
45 if !NATIVE_EXE_SUCCESS_EXIT_CODES.contains(&exit_code) {
46 bail!(
47 "native executable installer for {} failed with exit code {}",
48 package_name,
49 exit_code
50 );
51 }
52
53 let captured_metadata = capture_native_exe_metadata(package_name, install_dir);
54
55 if captured_metadata.is_none() {
56 warn!(
57 package = package_name,
58 install_dir = %install_dir.display(),
59 "native executable installer did not expose uninstall metadata"
60 );
61 }
62
63 let engine_metadata = captured_metadata.map(|metadata| match metadata {
64 NativeExeInstallMetadata::QuietOnly(command) => {
65 EngineMetadata::native_exe(Some(command), None)
66 }
67 NativeExeInstallMetadata::QuietAndStandard {
68 quiet_uninstall_command,
69 uninstall_command,
70 } => EngineMetadata::native_exe(Some(quiet_uninstall_command), Some(uninstall_command)),
71 NativeExeInstallMetadata::StandardOnly(command) => {
72 EngineMetadata::native_exe(None, Some(command))
73 }
74 });
75
76 Ok(EngineInstallReceipt::new(
77 EngineKind::NativeExe,
78 install_dir.to_string_lossy().into_owned(),
79 engine_metadata,
80 ))
81}